Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for encryption via pantalaimon #231

Merged
merged 33 commits into from
Sep 23, 2020
Merged

Conversation

Half-Shot
Copy link
Contributor

@Half-Shot Half-Shot commented Sep 15, 2020

This PR enables support for encryption for all bridges, designed to be a drop in upgrade and requiring a few options to be set.

Consequently there is a fair amount of callback fiddling and jumping around the stack to ensure that getIntent() continues to not make any calls until the user requires it, and that the bridge logs users in so they can interact with pan.

The meat of the changes lie in two places:

  • Intent has had it's ensureRegistered function modified to also set up encryption for the client. This involves causing it to fetch a session from a datastore, or log in otherwise.
  • A new class has appeared! EncryptedEventBroker. The broker tries to ensure that when an event arrives across the AS stream, the event is caught, and the correct event is fetched over sync and passed to onEvent. This involves some dances around retaining events temporarily in memory, and ensuring that only one event is ever handled.
  • Also added support for Typing/Presence/ReadReceipts from Matrix by pulling the info from /sync. This won't work for non-encryption users, but onEphemeralEvent can be used to handle these.

This PR relies on a few dependencies, which are noted in issue #230.

This PR will likely be the last thing to be merged, so this PR fixes #230.

@Half-Shot Half-Shot requested a review from jaller94 September 18, 2020 16:31
Copy link
Contributor

@jaller94 jaller94 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally good. I should give the Slack bridge a test on Monday (or when you're done).

src/components/membership-cache.ts Outdated Show resolved Hide resolved
src/components/encryption.ts Outdated Show resolved Hide resolved
}

export interface PresenceEvent {
content: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the bridge shall be able to deal with home servers that are not spec-compliant, all properties would be marked optional and tested to have the right type (including the root object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the bridge shall be able to deal with home servers that are not spec-compliant

We don't plan to do that at all. Writing a bridge would be a headache if that were the case :D. I've merely copied https://matrix.org/docs/spec/client_server/r0.6.0#m-presence which only has one required field.

encryption?: {
sessionPromise: Promise<ClientEncryptionSession|null>;
sessionCreatedCallback: (session: ClientEncryptionSession) => Promise<void>;
ensureSyncingCallback: () => Promise<void>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable naming: Having looked at all occurrences, I'm not really sure what ensureSyncingCallback means.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've renamed it to ensureClientSyncingCallback. Essentially, it ensures the intent's client is /syncing before it performs any encrypted actions.

src/components/intent.ts Outdated Show resolved Hide resolved
...result,
};
if (this.encryption) {
this.encryption.sessionPromise = Promise.resolve(session);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand what's happening here.
The encryption object is coming from opts, so I guess the parent of this object will later check this promise and get the value???

Why is this a promise and not the value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is a tricky one. In order to not break certain APIs, we have to ensure that the creation of an intent is not asynchronous. This means we can't do any store lookups, any API calls or anything until the intent is used. The problem with this is it means the first opportunity to do anything is in ensureRegistered, which is always called before we perform an intent action.

So things like the session which we need to pass to the client have to be passed as a promise to unwrap once we call ensureRegistered. Ideally we wouldn't be doing this at this stage, but it's that or breaking API compatibility, which felt like it would lead to a lot of work on the other bridges. On the whole passing a promise isn't the ultimate evil.

const encryptionOpts = this.opts.bridgeEncryption;
if (encryptionOpts) {
clientIntentOpts.encryption = {
sessionPromise: encryptionOpts.store.getStoredSession(userId),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess here lies the answer why sessionPromise is a promise and not directly the session value..
because we can't await the promise here and we want to forward any errors to the parent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, see above.

@Half-Shot
Copy link
Contributor Author

Note: We need matrix-js-sdk > 8.3.0 in order for this to work, but it hasn't been released yet. In order to make the CI pass I've included the latest, but we must be careful to only release a version of the bridge once the dependency has landed.

@Half-Shot Half-Shot changed the title WIP: Add support for encryption via pantalaimon Add support for encryption via pantalaimon Sep 23, 2020
@Half-Shot Half-Shot requested a review from jaller94 September 23, 2020 11:16
Copy link
Contributor

@jaller94 jaller94 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see anything wrong with this.

src/components/encryption.ts Outdated Show resolved Hide resolved
@Half-Shot
Copy link
Contributor Author

Half-Shot commented Sep 23, 2020

Shall merge once matrix-js-sdk has its RC out.

@Half-Shot Half-Shot merged commit 9f799ca into develop Sep 23, 2020
@Half-Shot Half-Shot deleted the hs/encryption-pan branch May 2, 2023 16:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Encrypted bridges
2 participants